package app

import (
	"fmt"
	"log"
	"regexp"
	"time"

	"gorm.io/driver/mysql"
	"gorm.io/gorm"
)

var _db *gorm.DB

func createDBConn() *gorm.DB {
	cfg := AppConfig.DB
	dsn := fmt.Sprintf("%v:%v@tcp(%v:%v)/%v?parseTime=True&loc=Local", cfg.User, cfg.Password, cfg.Host, cfg.Port, cfg.Name)

	db, err := gorm.Open(mysql.New(mysql.Config{
		DSN:                       dsn,   // data source name
		DefaultStringSize:         256,   // default size for string fields
		DisableDatetimePrecision:  true,  // disable datetime precision, which not supported before MySQL 5.6
		DontSupportRenameIndex:    true,  // drop & create when rename index, rename index not supported before MySQL 5.7, MariaDB
		DontSupportRenameColumn:   true,  // `change` when rename column, rename column not supported before MySQL 8, MariaDB
		SkipInitializeWithVersion: false, // auto configure based on currently MySQL version
	}), &gorm.Config{})
	if err != nil {
		log.Println("打开数据库失败：", err.Error())
		panic(err)
	}
	sqlDB, err := db.DB()
	// SetMaxIdleConns 设置空闲连接池中连接的最大数量
	sqlDB.SetMaxIdleConns(10)

	// SetMaxOpenConns 设置打开数据库连接的最大数量。
	sqlDB.SetMaxOpenConns(100)

	// SetConnMaxLifetime 设置了连接可复用的最大时间。
	sqlDB.SetConnMaxLifetime(time.Hour)

	return db
}

// GetDB 返回 gorm.DB 实例
func GetDB() *gorm.DB {
	if _db == nil {
		_db = createDBConn()
	}

	sqlDB, err := _db.DB()
	if err != nil {
		log.Println("DB ERROR ", err.Error())
		_db = createDBConn()
	}
	if err = sqlDB.Ping(); err != nil {
		log.Println("DB ERROR ", err.Error())
		_db = createDBConn()
	}
	return _db
}

// DB 查询方式
var DB = SQLHelper{}

// SQLHelper sql 辅助
type SQLHelper struct {
}

// HasInjectChar 是否含有主入字符
func (h SQLHelper) HasInjectChar(sourceString string) bool {
	str := `(?:')|(?:--)|(/\\*(?:.|[\\n\\r])*?\\*/)|(\b(select|update|and|or|delete|insert|trancate|char|chr|into|substr|ascii|declare|exec|count|master|into|drop|execute)\b)`
	re, err := regexp.Compile(str)
	if err != nil {
		panic(err.Error())
	}

	if re.MatchString(sourceString) {
		return true
	}
	return false
}

// 事务
// https://gorm.io/zh_CN/docs/transactions.html

// Select 查询 SQL 语句
func (h SQLHelper) Select(sql string, args ...interface{}) ([]map[string]interface{}, error) {
	db := GetDB()

	log.Println(sql, args)

	rows, err := db.Raw(sql, args...).Rows()
	if err != nil {
		return nil, err
	}
	defer rows.Close()

	list := []map[string]interface{}{}
	for rows.Next() {
		m := make(map[string]interface{})
		db.ScanRows(rows, &m)
		list = append(list, m)
	}
	return list, nil
}
